/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.hpvas.persistence.dao;

import java.io.Serializable;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import edu.hpvas.persistence.entity.Owner;
import edu.hpvas.persistence.entity.Person;
import java.util.ArrayList;
import java.util.Collection;
import edu.hpvas.persistence.entity.Veterinarian;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author raider
 */
public class PersonDAO implements Serializable {

    public PersonDAO() {
        this.emf = Persistence.createEntityManagerFactory("HPVAS");
    }
    
    private EntityManagerFactory emf;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Person person) throws Exception {
        if (person.getOwnerCollection() == null) {
            person.setOwnerCollection(new ArrayList<Owner>());
        }
        if (person.getVeterinarianCollection() == null) {
            person.setVeterinarianCollection(new ArrayList<Veterinarian>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<Owner> attachedOwnerCollection = new ArrayList<Owner>();
            for (Owner ownerCollectionOwnerToAttach : person.getOwnerCollection()) {
                ownerCollectionOwnerToAttach = em.getReference(ownerCollectionOwnerToAttach.getClass(), ownerCollectionOwnerToAttach.getId());
                attachedOwnerCollection.add(ownerCollectionOwnerToAttach);
            }
            person.setOwnerCollection(attachedOwnerCollection);
            Collection<Veterinarian> attachedVeterinarianCollection = new ArrayList<Veterinarian>();
            for (Veterinarian veterinarianCollectionVeterinarianToAttach : person.getVeterinarianCollection()) {
                veterinarianCollectionVeterinarianToAttach = em.getReference(veterinarianCollectionVeterinarianToAttach.getClass(), veterinarianCollectionVeterinarianToAttach.getId());
                attachedVeterinarianCollection.add(veterinarianCollectionVeterinarianToAttach);
            }
            person.setVeterinarianCollection(attachedVeterinarianCollection);
            em.persist(person);
            for (Owner ownerCollectionOwner : person.getOwnerCollection()) {
                Person oldIdPersonOfOwnerCollectionOwner = ownerCollectionOwner.getIdPerson();
                ownerCollectionOwner.setIdPerson(person);
                ownerCollectionOwner = em.merge(ownerCollectionOwner);
                if (oldIdPersonOfOwnerCollectionOwner != null) {
                    oldIdPersonOfOwnerCollectionOwner.getOwnerCollection().remove(ownerCollectionOwner);
                    oldIdPersonOfOwnerCollectionOwner = em.merge(oldIdPersonOfOwnerCollectionOwner);
                }
            }
            for (Veterinarian veterinarianCollectionVeterinarian : person.getVeterinarianCollection()) {
                Person oldIdPersonOfVeterinarianCollectionVeterinarian = veterinarianCollectionVeterinarian.getIdPerson();
                veterinarianCollectionVeterinarian.setIdPerson(person);
                veterinarianCollectionVeterinarian = em.merge(veterinarianCollectionVeterinarian);
                if (oldIdPersonOfVeterinarianCollectionVeterinarian != null) {
                    oldIdPersonOfVeterinarianCollectionVeterinarian.getVeterinarianCollection().remove(veterinarianCollectionVeterinarian);
                    oldIdPersonOfVeterinarianCollectionVeterinarian = em.merge(oldIdPersonOfVeterinarianCollectionVeterinarian);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findPerson(person.getId()) != null) {
                System.out.println("Person " + person + " already exists.");
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Person person) throws Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Person persistentPerson = em.find(Person.class, person.getId());
            Collection<Owner> ownerCollectionOld = persistentPerson.getOwnerCollection();
            Collection<Owner> ownerCollectionNew = person.getOwnerCollection();
            Collection<Veterinarian> veterinarianCollectionOld = persistentPerson.getVeterinarianCollection();
            Collection<Veterinarian> veterinarianCollectionNew = person.getVeterinarianCollection();
            Collection<Owner> attachedOwnerCollectionNew = new ArrayList<Owner>();
            for (Owner ownerCollectionNewOwnerToAttach : ownerCollectionNew) {
                ownerCollectionNewOwnerToAttach = em.getReference(ownerCollectionNewOwnerToAttach.getClass(), ownerCollectionNewOwnerToAttach.getId());
                attachedOwnerCollectionNew.add(ownerCollectionNewOwnerToAttach);
            }
            ownerCollectionNew = attachedOwnerCollectionNew;
            person.setOwnerCollection(ownerCollectionNew);
            Collection<Veterinarian> attachedVeterinarianCollectionNew = new ArrayList<Veterinarian>();
            for (Veterinarian veterinarianCollectionNewVeterinarianToAttach : veterinarianCollectionNew) {
                veterinarianCollectionNewVeterinarianToAttach = em.getReference(veterinarianCollectionNewVeterinarianToAttach.getClass(), veterinarianCollectionNewVeterinarianToAttach.getId());
                attachedVeterinarianCollectionNew.add(veterinarianCollectionNewVeterinarianToAttach);
            }
            veterinarianCollectionNew = attachedVeterinarianCollectionNew;
            person.setVeterinarianCollection(veterinarianCollectionNew);
            person = em.merge(person);
            for (Owner ownerCollectionOldOwner : ownerCollectionOld) {
                if (!ownerCollectionNew.contains(ownerCollectionOldOwner)) {
                    ownerCollectionOldOwner.setIdPerson(null);
                    ownerCollectionOldOwner = em.merge(ownerCollectionOldOwner);
                }
            }
            for (Owner ownerCollectionNewOwner : ownerCollectionNew) {
                if (!ownerCollectionOld.contains(ownerCollectionNewOwner)) {
                    Person oldIdPersonOfOwnerCollectionNewOwner = ownerCollectionNewOwner.getIdPerson();
                    ownerCollectionNewOwner.setIdPerson(person);
                    ownerCollectionNewOwner = em.merge(ownerCollectionNewOwner);
                    if (oldIdPersonOfOwnerCollectionNewOwner != null && !oldIdPersonOfOwnerCollectionNewOwner.equals(person)) {
                        oldIdPersonOfOwnerCollectionNewOwner.getOwnerCollection().remove(ownerCollectionNewOwner);
                        oldIdPersonOfOwnerCollectionNewOwner = em.merge(oldIdPersonOfOwnerCollectionNewOwner);
                    }
                }
            }
            for (Veterinarian veterinarianCollectionOldVeterinarian : veterinarianCollectionOld) {
                if (!veterinarianCollectionNew.contains(veterinarianCollectionOldVeterinarian)) {
                    veterinarianCollectionOldVeterinarian.setIdPerson(null);
                    veterinarianCollectionOldVeterinarian = em.merge(veterinarianCollectionOldVeterinarian);
                }
            }
            for (Veterinarian veterinarianCollectionNewVeterinarian : veterinarianCollectionNew) {
                if (!veterinarianCollectionOld.contains(veterinarianCollectionNewVeterinarian)) {
                    Person oldIdPersonOfVeterinarianCollectionNewVeterinarian = veterinarianCollectionNewVeterinarian.getIdPerson();
                    veterinarianCollectionNewVeterinarian.setIdPerson(person);
                    veterinarianCollectionNewVeterinarian = em.merge(veterinarianCollectionNewVeterinarian);
                    if (oldIdPersonOfVeterinarianCollectionNewVeterinarian != null && !oldIdPersonOfVeterinarianCollectionNewVeterinarian.equals(person)) {
                        oldIdPersonOfVeterinarianCollectionNewVeterinarian.getVeterinarianCollection().remove(veterinarianCollectionNewVeterinarian);
                        oldIdPersonOfVeterinarianCollectionNewVeterinarian = em.merge(oldIdPersonOfVeterinarianCollectionNewVeterinarian);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = person.getId();
                if (findPerson(id) == null) {
                    System.out.println("The person with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Person person = null;
            try {
                person = em.getReference(Person.class, id);
                person.getId();
            } catch (EntityNotFoundException enfe) {
                System.out.println("The person with id " + id + " no longer exists.");
            }
            Collection<Owner> ownerCollection = person.getOwnerCollection();
            for (Owner ownerCollectionOwner : ownerCollection) {
                ownerCollectionOwner.setIdPerson(null);
                ownerCollectionOwner = em.merge(ownerCollectionOwner);
            }
            Collection<Veterinarian> veterinarianCollection = person.getVeterinarianCollection();
            for (Veterinarian veterinarianCollectionVeterinarian : veterinarianCollection) {
                veterinarianCollectionVeterinarian.setIdPerson(null);
                veterinarianCollectionVeterinarian = em.merge(veterinarianCollectionVeterinarian);
            }
            em.remove(person);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Person> findPersonEntities() {
        return findPersonEntities(true, -1, -1);
    }

    public List<Person> findPersonEntities(int maxResults, int firstResult) {
        return findPersonEntities(false, maxResults, firstResult);
    }

    private List<Person> findPersonEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Person.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Person findPerson(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Person.class, id);
        } finally {
            em.close();
        }
    }
    
    public int getPersonCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Person> rt = cq.from(Person.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
